package com.example.base_model.sp

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.emptyPreferences
import androidx.datastore.preferences.preferencesDataStore
import com.blankj.utilcode.util.LogUtils
import com.example.base_model.sp.management_keys.AppPreferenceKey
import com.squareup.moshi.Moshi
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.map
import java.io.IOException
import javax.inject.Inject
import javax.inject.Singleton

/**
 * @Author jiangKunKun
 * @CreateDate 2025/8/6
 * @Description DataStore 管理类，用于保存和读取对象。
 * @SpittingGrooves
 */

/**
 * 为 [Context] 扩展属性 `dataStore`，用于方便地访问应用程序的 Preferences DataStore。
 * DataStore 名称为 "app_data_store"。
 */
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "app_data_store")

@Singleton // 标记为单例，由 Dagger Hilt 管理生命周期
class DataStoreManager @Inject constructor(
    @ApplicationContext val context: Context, // 注入 ApplicationContext
    val moshi: Moshi // 注入 Moshi 实例，用于 JSON 序列化和反序列化
) {
    /**
     * 保存一个对象。对象将被 Moshi 序列化为 JSON 字符串后存储到 DataStore。
     *
     * @param T 要保存的对象的类型。
     * @param preferenceKey [AppPreferenceKey] 枚举，定义了对象的存储键。
     * @param value 要保存的对象实例。
     */
    suspend inline fun <reified T : Any> saveObject(preferenceKey: AppPreferenceKey, value: T) {
        try {
            // 获取指定类型的 Moshi 适配器
            val adapter = moshi.adapter(T::class.java)
            // 将对象序列化为 JSON 字符串
            val jsonString = adapter.toJson(value)
            // 通过 DataStore 的 edit 方法存储数据
            context.dataStore.edit { preferences ->
                preferences[preferenceKey.stringKey()] = jsonString // 使用 AppPreferenceKey 的 stringKey 作为键
            }
        } catch (e: Exception) {
            // 记录保存对象时发生的错误
            LogUtils.d("DataStoreManager", "Failed to save object for key ${preferenceKey.rawValue}", e)
            // 抛出自定义异常，以便上层调用者处理
            throw DataStoreException("Failed to serialize or save object for key ${preferenceKey.rawValue}", e)
        }
    }

    /**
     * 读取一个对象。存储的 JSON 字符串将被 Moshi 反序列化为对象。
     *
     * @param T 要读取的对象的类型。
     * @param preferenceKey [AppPreferenceKey] 枚举，定义了对象的存储键。
     * @return [Flow<T?>] 发射对象实例，如果不存在或反序列化出错则发射 null。
     *         注意：如果提供了 non-null defaultValue，返回的 Flow 类型可以是 Flow<T>。
     *         为了简单起见，这里统一为 Flow<T?>，调用者可以使用 .map { it ?: defaultValue } 来提供默认值。
     */
    inline fun <reified T : Any> readObject(preferenceKey: AppPreferenceKey): Flow<T?> {
        // 获取指定类型的 Moshi 适配器
        val adapter = moshi.adapter(T::class.java)
        return context.dataStore.data
            .catch { exception ->
                // 记录读取对象时发生的错误
                LogUtils.d("DataStoreManager", "Error reading object for key ${preferenceKey.rawValue}", exception)
                if (exception is IOException) {
                    // 在 IO 异常时发射空偏好，允许下游处理，例如 DataStore 文件损坏
                    emit(emptyPreferences())
                } else {
                    // 抛出自定义异常，以便上层调用者处理其他类型的异常
                    throw DataStoreException("Failed to read object for key ${preferenceKey.rawValue}", exception)
                }
            }
            .map { preferences ->
                // 从 preferences 中获取 JSON 字符串
                val jsonString = preferences[preferenceKey.stringKey()]
                if (jsonString != null) {
                    try {
                        // 尝试将 JSON 字符串反序列化为对象
                        adapter.fromJson(jsonString)
                    } catch (e: Exception) {
                        // 记录反序列化失败的错误
                        LogUtils.d("DataStoreManager", "Failed to parse object for key ${preferenceKey.rawValue}", e)
                        null // 反序列化失败时返回 null
                    }
                } else {
                    null // 如果 Key 不存在，则返回 null
                }
            }
    }

    /**
     * 移除指定键存储的对象。
     *
     * @param preferenceKey [AppPreferenceKey] 枚举，定义了要移除的对象的存储键。
     */
    suspend fun removeObject(preferenceKey: AppPreferenceKey) {
        context.dataStore.edit { preferences ->
            preferences.remove(preferenceKey.stringKey()) // 移除指定键的数据
        }
    }

    /**
     * 清除所有由 DataStore 管理的 Preferences 数据。
     * 请谨慎使用此操作，因为它会删除所有存储的偏好设置！
     */
    suspend fun clearAllData() {
        context.dataStore.edit { preferences ->
            preferences.clear() // 清除所有数据
        }
    }

    /**
     * 检查指定的键是否存在数据。
     * @param preferenceKey [AppPreferenceKey] 枚举，定义了要检查的对象的存储键。
     * @return [Flow<Boolean>] 发射一个布尔值，表示该键是否存在数据。
     */
    fun objectExists(preferenceKey: AppPreferenceKey): Flow<Boolean> {
        return context.dataStore.data.map { preferences ->
            preferences.contains(preferenceKey.stringKey()) // 检查键是否存在
        }
    }
}

/**
 * 自定义异常，用于 [DataStoreManager] 操作失败时抛出。
 * @param message 异常消息。
 * @param cause 导致此异常的 Throwable 对象 (可选)。
 */
class DataStoreException(message: String, cause: Throwable? = null) : RuntimeException(message, cause)